#include "StompedReality/Core/TypeSystem/TypeSystem.h"
#include "StomperLib/Objects/EditorObjectList.h"
#include <fstream>
namespace StomperLib {
EditorObjectList::EditorObjectList( Gwen::Controls::Base* base ) : Gwen::Controls::Base( base )
{
  m_SelectedObjectIndex = -1;
}

EditorObjectList::~EditorObjectList( )
{
  for ( auto iter = this->m_EditorObjects.begin( ); iter != this->m_EditorObjects.end( ); ++iter)
  {
    delete *iter;
    *iter = NULL;
  }
  this->m_EditorObjects.clear( );
}

std::vector<StomperLib::EditorObjectInfo*>::iterator EditorObjectList::Begin( )
{
  return this->m_EditorObjects.begin( );
}

std::vector<StomperLib::EditorObjectInfo*>::iterator EditorObjectList::End( )
{
  return this->m_EditorObjects.end( );
}

int EditorObjectList::Size( )
{
  return this->m_EditorObjects.size( );
}

int EditorObjectList::SelectedObjectIndex( )
{
  return this->m_SelectedObjectIndex;
}

void EditorObjectList::Clear( )
{
  this->m_EditorObjects.clear( );
  this->UnselectObject( );
}

int EditorObjectList::Add( StomperLib::EditorObjectInfo* obj )
{
  int size = this->m_EditorObjects.size( );
  this->m_EditorObjects.push_back( obj );
  return size;
}

StomperLib::EditorObjectInfo* EditorObjectList::Remove( int index )
{
  if (index >= this->m_EditorObjects.size( ))
    return NULL;

  StomperLib::EditorObjectInfo* obj = this->m_EditorObjects[index];
  this->m_EditorObjects.erase( this->m_EditorObjects.begin( )+index );

  if (m_SelectedObjectIndex == index)
    this->UnselectObject( );

  if (m_SelectedObjectIndex > index)
    m_SelectedObjectIndex--;

  return obj;
}

StomperLib::EditorObjectInfo* EditorObjectList::SelectObject( int index )
{
  if (index < this->m_EditorObjects.size( ) && index >= 0)
  {
    this->m_SelectedObjectIndex = index;
    return this->GetSelectedObject( );
  }
  else
  {
    return NULL;
  }
}

void EditorObjectList::UnselectObject( )
{
  this->m_SelectedObjectIndex = -1;
  this->onSelectionChange.Call( this );
}

StomperLib::EditorObjectInfo* EditorObjectList::GetSelectedObject( )
{
  if (this->m_SelectedObjectIndex == -1)
    return NULL;
  return this->m_EditorObjects[this->m_SelectedObjectIndex];
}

StomperLib::EditorObjectInfo* EditorObjectList::Get( int index )
{
  if (index < this->m_EditorObjects.size( ) && index >= 0)
  {
    return this->m_EditorObjects[index];
  }
  else
  {
    return NULL;
  }
}

bool EditorObjectList::IsObjectSelected( )
{
  return this->m_SelectedObjectIndex != -1;
}

int EditorObjectList::GetSelectedObjectIndex( )
{
  return this->m_SelectedObjectIndex;
}

bool EditorObjectList::Contains( std::function<bool(StomperLib::EditorObjectInfo*)> compare )
{
  bool contains = false;
  for (auto iter = this->m_EditorObjects.begin( ); iter != this->m_EditorObjects.end( ); ++iter)
  {
    if (compare( *iter ))
      return true;
  }
  return false;
}

int EditorObjectList::FindIndex( std::function<bool(StomperLib::EditorObjectInfo*)> function )
{
  for (int i = 0; i < this->Size( ); ++i)
  {
    if (function( m_EditorObjects[i] ))
      return i;
  }
  return -1;
}

int EditorObjectList::Select( std::function<bool(StomperLib::EditorObjectInfo*)> function )
{
  int selectedIndex = this->GetSelectedObjectIndex( );

  this->m_SelectedObjectIndex = this->FindIndex( function );

  if (selectedIndex != this->GetSelectedObjectIndex( ))
    this->onSelectionChange.Call( this );

  return SelectedObjectIndex( );
}

Json::Value EditorObjectList::CreateJson( )
{
  Json::Value root;
  for (auto obj = this->m_EditorObjects.begin( ); obj != this->m_EditorObjects.end( ); ++obj)
  {
    StompedReality::type_system::TypeInfo* info = StompedReality::type_system::TypeSystem::GetTypeByName(
        (*obj)->TypeName.c_str( ));
    if (info == NULL)
      continue;
    Json::Value objRoot;
    info->write( objRoot, (char*) *obj );
    root.append( objRoot );
  }
  return root;
}

void EditorObjectList::ParseJson( Json::Value& root )
{
  for (unsigned int i = 0; i < root.size( ); ++i)
  {
    StompedReality::type_system::TypeInfo* info =
      StompedReality::type_system::TypeSystem::GetTypeByName( root[i]["type"].asCString( ));
    if (info == NULL)
      continue;

    int s = info->size;
    StomperLib::EditorObjectInfo* obj = (StomperLib::EditorObjectInfo*) info->newPtr( );
    info->read( root[i], (char*)obj );
    this->Add( obj );
  }
}

}